home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1992, Brian Berliner and Jeff Polk
- *
- * You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS 1.3 kit.
- *
- * General recursion handler
- *
- */
-
- #include "cvs.h"
-
- #ifndef lint
- static char rcsid[] = "@(#)recurse.c 1.22 92/04/10";
- #endif
-
- #if __STDC__
- static int do_dir_proc (Node * p);
- static int do_file_proc (Node * p);
- static void addlist (List ** listp, char *key);
- #else
- static int do_file_proc ();
- static int do_dir_proc ();
- static void addlist ();
- #endif /* __STDC__ */
-
-
- /*
- * Local static versions eliminates the need for globals
- */
- static int (*fileproc) ();
- static int (*filesdoneproc) ();
- static Dtype (*direntproc) ();
- static int (*dirleaveproc) ();
- static int which;
- static Dtype flags;
- static int aflag;
- static int readlock;
- static int dosrcs;
- static char update_dir[PATH_MAX];
- static char *repository = NULL;
- static List *entries = NULL;
- static List *srcfiles = NULL;
- static List *filelist = NULL;
- static List *dirlist = NULL;
-
- /*
- * Called to start a recursive command Command line arguments are processed
- * if present, otherwise the local directory is processed.
- */
- int
- start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
- argc, argv, local, which, aflag, readlock,
- update_preload, dosrcs)
- int (*fileproc) ();
- int (*filesdoneproc) ();
- Dtype (*direntproc) ();
- int (*dirleaveproc) ();
- int argc;
- char *argv[];
- int local;
- int which;
- int aflag;
- int readlock;
- char *update_preload;
- int dosrcs;
- {
- int i, err = 0;
- Dtype flags;
-
- if (update_preload == NULL)
- update_dir[0] = '\0';
- else
- (void) strcpy (update_dir, update_preload);
-
- if (local)
- flags = R_SKIP_DIRS;
- else
- flags = R_PROCESS;
-
- /* clean up from any previous calls to start_recursion */
- if (repository)
- {
- free (repository);
- repository = (char *) NULL;
- }
- if (entries)
- dellist (&entries);
- if (srcfiles)
- dellist (&srcfiles);
- if (filelist)
- dellist (&filelist);
- if (dirlist)
- dellist (&dirlist);
-
- if (argc == 0)
- {
-
- /*
- * There were no arguments, so we'll probably just recurse. The
- * exception to the rule is when we are called from a directory
- * without any CVS administration files. That has always meant to
- * process each of the sub-directories, so we pretend like we were
- * called with the list of sub-dirs of the current dir as args
- */
- if ((which & W_LOCAL) && !isdir (CVSADM) && !isdir (OCVSADM))
- dirlist = Find_Dirs ((char *) NULL, W_LOCAL);
- else
- addlist (&dirlist, ".");
-
- err += do_recursion (fileproc, filesdoneproc, direntproc,
- dirleaveproc, flags, which, aflag,
- readlock, dosrcs);
- }
- else
- {
-
- /*
- * There were arguments, so we have to handle them by hand. To do
- * that, we set up the filelist and dirlist with the arguments and
- * call do_recursion. do_recursion recognizes the fact that the
- * lists are non-null when it starts and doesn't update them
- */
-
- /* look for args with /-s in them */
- for (i = 0; i < argc; i++)
- if (index (argv[i], '/') != NULL)
- break;
-
- /* if we didn't find any hard one's, do it the easy way */
- if (i == argc)
- {
- /* set up the lists */
- for (i = 0; i < argc; i++)
- {
- if (isdir (argv[i]))
- addlist (&dirlist, argv[i]);
- else
- {
- if (isdir (CVSADM) || isdir (OCVSADM))
- {
- char *repos;
- char tmp[PATH_MAX];
-
- repos = Name_Repository ((char *) NULL, update_dir);
- (void) sprintf (tmp, "%s/%s", repos, argv[i]);
- if (isdir (tmp))
- addlist (&dirlist, argv[i]);
- else
- addlist (&filelist, argv[i]);
- free (repos);
- }
- else
- addlist (&filelist, argv[i]);
- }
- }
-
- /* we aren't recursive if no directories were specified */
- if (dirlist == NULL)
- local = 1;
-
- /* process the lists */
- err += do_recursion (fileproc, filesdoneproc, direntproc,
- dirleaveproc, flags, which, aflag,
- readlock, dosrcs);
- }
- /* otherwise - do it the hard way */
- else
- {
- char *cp;
- char *dir = (char *) NULL;
- char *comp = (char *) NULL;
- char *oldupdate = (char *) NULL;
- char savewd[PATH_MAX];
-
- if (getwd (savewd) == NULL)
- error (1, 0, "could not get working directory: %s", savewd);
-
- for (i = 0; i < argc; i++)
- {
- /* split the arg into the dir and component parts */
- dir = xstrdup (argv[i]);
- if ((cp = rindex (dir, '/')) != NULL)
- {
- *cp = '\0';
- comp = xstrdup (cp + 1);
- oldupdate = xstrdup (update_dir);
- if (update_dir[0] != '\0')
- (void) strcat (update_dir, "/");
- (void) strcat (update_dir, dir);
- }
- else
- {
- comp = xstrdup (dir);
- if (dir)
- free (dir);
- dir = (char *) NULL;
- }
-
- /* chdir to the appropriate place if necessary */
- if (dir && chdir (dir) < 0)
- error (1, errno, "could not chdir to %s", dir);
-
- /* set up the list */
- if (isdir (comp))
- addlist (&dirlist, comp);
- else
- {
- if (isdir (CVSADM) || isdir (OCVSADM))
- {
- char *repos;
- char tmp[PATH_MAX];
-
- repos = Name_Repository ((char *) NULL, update_dir);
- (void) sprintf (tmp, "%s/%s", repos, comp);
- if (isdir (tmp))
- addlist (&dirlist, comp);
- else
- addlist (&filelist, comp);
- free (repos);
- }
- else
- addlist (&filelist, comp);
- }
-
- /* do the recursion */
- err += do_recursion (fileproc, filesdoneproc, direntproc,
- dirleaveproc, flags, which,
- aflag, readlock, dosrcs);
-
- /* chdir back and fix update_dir if necessary */
- if (dir && chdir (savewd) < 0)
- error (1, errno, "could not chdir to %s", dir);
- if (oldupdate)
- {
- (void) strcpy (update_dir, oldupdate);
- free (oldupdate);
- }
-
- }
- if (dir)
- free (dir);
- if (comp)
- free (comp);
- }
- }
- return (err);
- }
-
- /*
- * Implement the recursive policies on the local directory. This may be
- * called directly, or may be called by start_recursion
- */
- int
- do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc,
- xflags, xwhich, xaflag, xreadlock, xdosrcs)
- int (*xfileproc) ();
- int (*xfilesdoneproc) ();
- Dtype (*xdirentproc) ();
- int (*xdirleaveproc) ();
- Dtype xflags;
- int xwhich;
- int xaflag;
- int xreadlock;
- int xdosrcs;
- {
- int err = 0;
- int dodoneproc = 1;
- char *srepository;
-
- /* do nothing if told */
- if (xflags == R_SKIP_ALL)
- return (0);
-
- /* set up the static vars */
- fileproc = xfileproc;
- filesdoneproc = xfilesdoneproc;
- direntproc = xdirentproc;
- dirleaveproc = xdirleaveproc;
- flags = xflags;
- which = xwhich;
- aflag = xaflag;
- readlock = noexec ? 0 : xreadlock;
- dosrcs = xdosrcs;
-
- /*
- * Fill in repository with the current repository
- */
- if (which & W_LOCAL)
- {
- if (isdir (CVSADM) || isdir (OCVSADM))
- repository = Name_Repository ((char *) NULL, update_dir);
- else
- repository = NULL;
- }
- else
- {
- repository = xmalloc (PATH_MAX);
- (void) getwd (repository);
- }
- srepository = repository; /* remember what to free */
-
- /*
- * The filesdoneproc needs to be called for each directory where files
- * processed, or each directory that is processed by a call where no
- * directories were passed in. In fact, the only time we don't want to
- * call back the filesdoneproc is when we are processing directories that
- * were passed in on the command line (or in the special case of `.' when
- * we were called with no args
- */
- if (dirlist != NULL && filelist == NULL)
- dodoneproc = 0;
-
- /*
- * If filelist or dirlist is already set, we don't look again. Otherwise,
- * find the files and directories
- */
- if (filelist == NULL && dirlist == NULL)
- {
- /* both lists were NULL, so start from scratch */
- if (fileproc != NULL && flags != R_SKIP_FILES)
- {
- int lwhich = which;
-
- /* be sure to look in the attic if we have sticky tags/date */
- if ((lwhich & W_ATTIC) == 0)
- if (isreadable (CVSADM_TAG))
- lwhich |= W_ATTIC;
-
- /* find the files and fill in entries if appropriate */
- filelist = Find_Names (repository, lwhich, aflag, &entries);
- }
-
- /* find sub-directories if we will recurse */
- if (flags != R_SKIP_DIRS)
- dirlist = Find_Dirs (repository, which);
- }
- else
- {
- /* something was passed on the command line */
- if (filelist != NULL && fileproc != NULL)
- {
- /* we will process files, so pre-parse entries */
- if (which & W_LOCAL)
- entries = ParseEntries (aflag);
- }
- }
-
- /* process the files (if any) */
- if (filelist != NULL)
- {
- /* read lock it if necessary */
- if (readlock && repository && Reader_Lock (repository) != 0)
- error (1, 0, "read lock failed - giving up");
-
- /* pre-parse the source files */
- if (dosrcs && repository)
- srcfiles = RCS_parsefiles (filelist, repository);
- else
- srcfiles = (List *) NULL;
-
- /* process the files */
- err += walklist (filelist, do_file_proc);
-
- /* unlock it */
- if (readlock)
- Lock_Cleanup ();
-
- /* clean up */
- dellist (&filelist);
- dellist (&srcfiles);
- dellist (&entries);
- }
-
- /* call-back files done proc (if any) */
- if (dodoneproc && filesdoneproc != NULL)
- err = filesdoneproc (err, repository, update_dir[0] ? update_dir : ".");
-
- /* process the directories (if necessary) */
- if (dirlist != NULL)
- err += walklist (dirlist, do_dir_proc);
- #ifdef notdef
- else if (dirleaveproc != NULL)
- err += dirleaveproc(".", err, ".");
- #endif
- dellist (&dirlist);
-
- /* free the saved copy of the pointer if necessary */
- if (srepository)
- {
- (void) free (srepository);
- repository = (char *) NULL;
- }
-
- return (err);
- }
-
- /*
- * Process each of the files in the list with the callback proc
- */
- static int
- do_file_proc (p)
- Node *p;
- {
- if (fileproc != NULL)
- return (fileproc (p->key, update_dir, repository, entries, srcfiles));
- else
- return (0);
- }
-
- /*
- * Process each of the directories in the list (recursing as we go)
- */
- static int
- do_dir_proc (p)
- Node *p;
- {
- char *dir = p->key;
- char savewd[PATH_MAX];
- char newrepos[PATH_MAX];
- List *sdirlist;
- char *srepository;
- char *cp;
- Dtype dir_return = R_PROCESS;
- int stripped_dot = 0;
- int err = 0;
-
- /* set up update_dir - skip dots if not at start */
- if (strcmp (dir, ".") != 0)
- {
- if (update_dir[0] != '\0')
- {
- (void) strcat (update_dir, "/");
- (void) strcat (update_dir, dir);
- }
- else
- (void) strcpy (update_dir, dir);
-
- /*
- * Here we need a plausible repository name for the sub-directory. We
- * create one by concatenating the new directory name onto the
- * previous repository name. The only case where the name should be
- * used is in the case where we are creating a new sub-directory for
- * update -d and in that case the generated name will be correct.
- */
- if (repository == NULL)
- newrepos[0] = '\0';
- else
- (void) sprintf (newrepos, "%s/%s", repository, dir);
- }
- else
- {
- if (update_dir[0] == '\0')
- (void) strcpy (update_dir, dir);
-
- if (repository == NULL)
- newrepos[0] = '\0';
- else
- (void) strcpy (newrepos, repository);
- }
-
- /* call-back dir entry proc (if any) */
- if (direntproc != NULL)
- dir_return = direntproc (dir, newrepos, update_dir);
-
- /* only process the dir if the return code was 0 */
- if (dir_return != R_SKIP_ALL)
- {
- /* save our current directory and static vars */
- if (getwd (savewd) == NULL)
- error (1, 0, "could not get working directory: %s", savewd);
- sdirlist = dirlist;
- srepository = repository;
- dirlist = NULL;
-
- /* cd to the sub-directory */
- if (chdir (dir) < 0)
- error (1, errno, "could not chdir to %s", dir);
-
- /* honor the global SKIP_DIRS (a.k.a. local) */
- if (flags == R_SKIP_DIRS)
- dir_return = R_SKIP_DIRS;
-
- /* remember if the `.' will be stripped for subsequent dirs */
- if (strcmp (update_dir, ".") == 0)
- {
- update_dir[0] = '\0';
- stripped_dot = 1;
- }
-
- /* make the recursive call */
- err += do_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
- dir_return, which, aflag, readlock, dosrcs);
-
- /* put the `.' back if necessary */
- if (stripped_dot)
- (void) strcpy (update_dir, ".");
-
- /* call-back dir leave proc (if any) */
- if (dirleaveproc != NULL)
- err = dirleaveproc (dir, err, update_dir);
-
- /* get back to where we started and restore state vars */
- if (chdir (savewd) < 0)
- error (1, errno, "could not chdir to %s", savewd);
- dirlist = sdirlist;
- repository = srepository;
- }
-
- /* put back update_dir */
- if ((cp = rindex (update_dir, '/')) != NULL)
- *cp = '\0';
- else
- update_dir[0] = '\0';
-
- return (err);
- }
-
- /*
- * Add a node to a list allocating the list if necessary
- */
- static void
- addlist (listp, key)
- List **listp;
- char *key;
- {
- Node *p;
-
- if (*listp == NULL)
- *listp = getlist ();
- p = getnode ();
- p->type = FILES;
- p->key = xstrdup (key);
- (void) addnode (*listp, p);
- }
-